
//
//  BaseModelObject.m
//  Runtime给Model赋值
//
//  Created by MyMac on 15/8/11.
//  Copyright (c) 2015年 MyMac. All rights reserved.
//

#import "BaseModelObject.h"
#import <objc/runtime.h>
@implementation BaseModelObject
/**
 *  传入一个属性名，生成该实体类（子类）属性的set方法
 */
-(SEL)creatSetterWithPropertyName:(NSString*)propertyName
{
    //首字母大写
    propertyName=propertyName.capitalizedString;
    
    
    //拼接上set关键字
    propertyName=[NSString stringWithFormat:@"set%@:",propertyName];
    
    
    //返回set方法
    return NSSelectorFromString(propertyName);


}



/**
 *  调用这个方法，，，传入一个字典，把字典的值赋给实体类对应的属性，，，，对应关系是字典的key与实体类的属性名相同，否则抱错,所以此方法必须在实体类的属性名与字典的key相同的情况下调用
 *
 *  @param data 要付给实体类属性的字典
 */
-(void)assginToPropertyWithDictionary:(NSDictionary*)data
{
    if (data==nil) {
        return;
    }
    NSArray*dicKey=[data allKeys];
    
    //循环便利字典的key，并且动态的生成实体类（子类）的setter方法，把字典的value通过setter 方法赋值给实体类的属性
    for (NSUInteger i=0; i<dicKey.count; i++) {
        SEL setSel=[self creatSetterWithPropertyName:dicKey[i]];
        
        
        //如果字典key与属性名不相同，就不会走这个方法
        if([self respondsToSelector:setSel]){
            //获取字典key对应的value
            NSString*value=[NSString stringWithFormat:@"%@",data[dicKey[i]]];
            
            
            //把值通过set方法赋给实体类对应的属性
            [self performSelectorOnMainThread:setSel withObject:value waitUntilDone:[NSThread isMainThread]];
        
        }
    }
}
/**
 *  通过映射关系把字典的key转换成与property 的名字一样的字典，然后调用赋值方法
 *
 *  @param data <#data description#>
 */
-(void)assginToPropertyWithNoMapDictionary:(NSDictionary*)data
{
    //获取字典与model的映射关系，，，子类要重写这个方法，，因为基类返回的是nil;,返回的字典中，key代表原字典的key，value代表model的属性名
    NSDictionary*propertyMapDic=[self propertyMapDic];
    
    
    //将字典的key转换成与属性名一样的字典，然后调用assginToPropertyWithDictionary方法
    NSArray*dicKey=[data allKeys];
    NSMutableDictionary*tempDic=[[NSMutableDictionary alloc]initWithCapacity:dicKey.count];
    for (int i=0; i<dicKey.count; i++) {
        if(i<dicKey.count){
        NSString*key=dicKey[i];
            NSString*modelKey=propertyMapDic[key];
            NSString*modelValue=data[key];
        if(modelKey!=nil&&modelValue!=nil){
        [tempDic setObject:modelValue forKey:modelKey];
         
        }
    }
    }
    [self assginToPropertyWithDictionary:tempDic];



}

-(instancetype)initWithDictionary:(NSDictionary*)data;
{
    self=[super init];
    if(self){
        if([self propertyMapDic]==nil){
        //没有映射关系调用
        [self assginToPropertyWithDictionary:data];
        }else{
        //有映射关系调用，即传入的字典key与属性名不相同，子类重写了propertyMapDic才会不为nil
        [self assginToPropertyWithNoMapDictionary:data];
        
        }
    
    
    }
    return self;

}
+(instancetype)modelWithDictionary:(NSDictionary *)data
{


    return [[self alloc]initWithDictionary:data];



}
/**
 *  获取当前对象的类的所有属性的名称，以数组的形式返回
 */
-(NSArray*)allPropertyNames
{
    NSMutableArray*allNames=[[NSMutableArray alloc]init];
    //存储属性的个数
    unsigned int propertyCount=0;
    
  
    //通过运行时获取当前类的属性
    objc_property_t*propertys=class_copyPropertyList([self class], &propertyCount);
    
    
    //把属性放到数组中
    for (int i=0; i<propertyCount; i++) {
        //取出属性
        objc_property_t property=propertys[i];
        
        const char*propertyName=property_getName(property);
        
    
        
        
        [allNames addObject:[NSString stringWithUTF8String:propertyName]];
        
    }
    free(propertys);
    return allNames;
}

/**
 *  传入一个属性名，，，返回该属性的get方法
 *
 *  @param propertyName 属性名
 *
 *  @return 该属性的get方法
 */
-(SEL)createGetterWithPropertyName:(NSString*)propertyName
{
   //get方法的形式与属性名相同，，，直接生成

    return NSSelectorFromString(propertyName);



}
/**
 *  通过runtime来执行Getter方法，这一块需要通过方法的签名来执行getter方法
 
 在OC的运行时中，要执行的方法需要传入参数多余1个，或者需要接收返回值时，需要方法的签名来调用方法，，，，Getter方法有返回值，所以需要通过方法的签名来调用方法
 
 此方法就是创建方法的签名，然后通过签名来获取调用的对象
 
 
 获取该对象属性的值，是.h中声明的
 
 */
-(id)displayCurrentModelPropertyName:(NSString*)propertyName{
//    //获取实体类的全部属性名
//    NSArray*array=[self allPropertyNames];
//    
//    //装属性值
//    NSMutableArray*resultArray=[[NSMutableArray alloc]init];
//    for (int i=0;i< array.count; i++) {
//        //获取get方法
        SEL getSel=[self createGetterWithPropertyName:propertyName];
        if([self respondsToSelector:getSel]){
        
        //获得类和方法的签名
            NSMethodSignature*signature=[self methodSignatureForSelector:getSel];
        //从签名获得调用对象
            NSInvocation*invocation=[NSInvocation invocationWithMethodSignature:signature];
        //设置target
            [invocation setTarget:self];
  
        //设置selector
            [invocation setSelector:getSel];
        
        //接收返回的值
            NSObject*__unsafe_unretained returnValue=nil;
        
        //调用
            [invocation invoke];
        
            
            
        //接收返回值
            [invocation getReturnValue:&returnValue];
            return returnValue;
//            if(returnValue!=nil){
//            [resultArray addObject:returnValue];
            }
//
//        }
//    }


    return nil;

}


/**
 *  属性和字典key的映射关系
 *
 *  @return 映射的字典
 
 
 在model的基类中添加一个返回映射字典的方法，然后在子类中进行重写，这个映射方法在基类中返回nil，如果子类需要重写的话就对这个方法进行重写，并返回映射字典
 */
-(NSDictionary*)propertyMapDic;
{
    return nil;

}




-(NSString*)description
{
    NSArray*propertys=[self allPropertyNames];
    NSMutableString*resule=[NSMutableString string];
    for (int i=0; i<propertys.count; i++) {
        NSString*key=propertys[i];
       // NSString*value=[self performSelector:[self createGetterWithPropertyName:key] withObject:nil];//貌似也可以直接调get方法，不报错
        id value=[self displayCurrentModelPropertyName:key];
        [resule appendFormat:@"%@:%@\n",key,value];
    }
    return resule;




}
@end
